﻿using System;
using System.Collections.Generic;
using System.Text;
namespace FinalProjectLogicLayer
{
    /// <summary>
    /// This class has few string matching methods that use different algorithems
    /// </summary>
    public class StringMatching
    {
        public Dictionary Dictionary
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }
        /// <summary>
        /// This is the maximum number of allowed characters 
        /// </summary>
        private static int CHAR_MAX = 256;
        /// <summary>
        /// This method returns the calculated cs vector of the last run
        /// </summary>
        public void GetCSVector()
        {
            throw new System.NotImplementedException();
        }
        /// <summary>
        /// This method findes the number of occurences of a pattern in a text allowing approximate matching this method chooses the best algorithem to use
        /// </summary>
        /// <param name="pattern">Pattern to search for</param>
        /// <param name="text">The text to search in</param>
        /// <param name="errorsAllowed">number of errors allowed for the approximate matching</param>
        /// <returns>Number of approximate pattern matches</returns>
        public static int search(String text, String pattern, int errorsAllowed)
        {
            if (pattern.Length<6)
                return bruteForce_approximate_search(text,pattern,errorsAllowed);
            else
                return bitapFuzzyBitwizeSearch(text, pattern, errorsAllowed);
        }
        /// <summary>
        /// This method uses bruteForce O(text length * pattern length) to fine approximate matches allowing errors
        /// </summary>
        /// <param name="text"> Text to search in </param>
        /// <param name="pattern">Pattern to find in the text (allowing erros)</param>
        /// <param name="k"> allowed number of errors</param> 
        /// <returns> number of matches</returns>
        public static int bruteForce_approximate_search(String text, String pattern, int errorsAllowed)
        {         
            int textLength = text.Length;
            int patternLength = pattern.Length;
            int incorrectCharacterInText;
            int patternMatchsCounter = 0;
            textLength -= patternLength;


            for (int i = 0; i <= textLength; i++) //go over all letter of the text
            {
                incorrectCharacterInText = 0;   //reset error counter
                for (int j = 0; j < patternLength; j++) //go over all letter of pattern
                {
                    if(pattern[j]!=text[i+j])
                        incorrectCharacterInText++; 
                } //end of pattern loop
                if (incorrectCharacterInText <= errorsAllowed)
                    patternMatchsCounter++;
            } //end of text search
            return patternMatchsCounter;
        }

        /// <summary>
        /// This method is the fuzzy string matching that is using the bitap algorithem
        /// </summary>
        /// <param name="text"> Text to search in </param>
        /// <param name="pattern">Pattern to find in the text (allowing erros)</param>
        /// <param name="k"> allowed number of errors</param> 
        /// <returns> number of matches</returns>
        public  static int bitapFuzzyBitwizeSearch(String text,String pattern,int k)
        {
         
            int m = pattern.Length;
            int matchCounter =0;
            long [] R;

            long[] pattern_mask = new long[CHAR_MAX + 1];
            int i, d;
         
            if (pattern[0] == '\0') return 0;
           
            //if (m > 31) return "The pattern is too long!"; //Works well even with out this line
         
            R = new long[k + 1]; // Initialize the bit array R

             for (i=0; i <= k; ++i)
                 R[i] = ~1;         //..FFFFFE 
             /* Initialize the pattern bitmasks */
             for (i=0; i <= CHAR_MAX; ++i)
                pattern_mask[i] = ~0; //..FFFFFFF
             for (i=0; i < m; ++i)
                 pattern_mask[pattern[i]] &= ~(1L << i);
             for (i=0; i<text.Length; ++i) 
             {
                 /* Update the bit arrays */
                 long old_Rd1 = R[0];
                 R[0] |= pattern_mask[text[i]];
                 R[0] <<= 1;
                 for (d=1; d <= k; ++d)
                 {
                     long tmp = R[d];
                     /* Substitution is all we care about */
                     R[d] = (old_Rd1 & (R[d] | pattern_mask[text[i]])) << 1;
                     old_Rd1 = tmp;
                 }
                 if (0 == (R[k] & (1L << m)))
                 {
                     matchCounter++;
                    // result = text.Substring(i-m + 1,m);
                    // break;
                 }
             }
             return matchCounter;
        }

        public static void createTestTxtFile(String filename,int numberOfRepeates,bool random)
        {
            System.IO.File.Delete(filename); //delete old test file
            System.IO.FileStream testFile = System.IO.File.OpenWrite(filename); //crete a new file

            if (random)
            {//create a file with random letters
                Random randomNum = new Random();
                for (int i = 0; i < numberOfRepeates; i++)
                {


                    testFile.WriteByte((byte)(char)randomNum.Next(65, 123));
                }
            }
            else
            {
                for (int i = 0; i < numberOfRepeates; i++)
                {

                    testFile.WriteByte((byte)'a');
                    testFile.WriteByte((byte)'b');
                }
            }
            
            testFile.Close();
        }

    }
}
